#include "stdafx.h"
#include "reload_interface.h"

#define MAX_ARRAY_LENGTH	1024

#define LOG

void get_register_server(const char *overlay_name, const char *resource_key, char *result)
{
	if(overlay_name == NULL || resource_key == NULL)
		return;

	LOG("get_register_server: overlay_name %s,  resource_key %s\n", overlay_name, resource_key);

	boost::uuids::random_generator gen;
	boost::uuids::uuid register_queue_id = gen();
	std::stringstream ss;
  ss << register_queue_id;
	IPCCall::IPCCallPacketBase request_packet;
	request_packet.messageQueueName_.setValue(ss.str());
	request_packet.overlayInstanceName_.setValue(overlay_name);
	request_packet.resourceName_.setValue(resource_key);

	std::vector<IPCCall::byte> request_buffer(request_packet.size());
	boost::shared_ptr<IPCCall::IoBuffer> ptr_request_buffer(new IPCCall::IoBuffer(&request_buffer));
	ptr_request_buffer->clear();
	request_packet.writeToBuffer(ptr_request_buffer);

	try
	{
		boost::interprocess::message_queue::remove(ss.str().c_str());
		boost::interprocess::message_queue register_queue(boost::interprocess::create_only, ss.str().c_str(), 10, IPCCall::maxMessageSize);

		LOG( "get_register_server:create random register message queue success, queue name [ %s ]!\n", ss.str().c_str());

		boost::interprocess::message_queue reload_queue(boost::interprocess::open_only, IPCCall::sendAppAttachReqMessageQueueName_.c_str());
		boost::posix_time::ptime current_time = boost::posix_time::second_clock::local_time();
		boost::posix_time::ptime end_time = current_time + boost::posix_time::seconds(10);
		if(!reload_queue.timed_send(&request_buffer[0], request_packet.size(), 0, end_time))
		{
			boost::interprocess::message_queue::remove(ss.str().c_str());
			LOG( "get_register_server: reload message is full, can't send message timely!\n");
			return;
		}
		else
			LOG( "get_register_server:open reload message queue success!\n");

		std::vector<IPCCall::byte> response_buffer(IPCCall::maxMessageSize);
		boost::shared_ptr<IPCCall::IoBuffer> ptr_response_buffer(new IPCCall::IoBuffer(&response_buffer));
		ptr_response_buffer->clear();

		//boost::interprocess::message_queue register_queue(boost::interprocess::open_only, ss.str().c_str());
		unsigned int priority;
		std::size_t received_size;
		current_time = boost::posix_time::second_clock::local_time();
		end_time = current_time + boost::posix_time::seconds(10);
		if(!register_queue.timed_receive(ptr_response_buffer->data(), ptr_response_buffer->capacity(),received_size,  priority, end_time))
		{
			boost::interprocess::message_queue::remove(ss.str().c_str());
			LOG( "get_register_server: don't receive message in time, we return directly!\n");
			return;
		}
		ptr_response_buffer->produce(received_size);
		IPCCall::SendAppAttachReqIPCCallResult attach_response;
		attach_response.readFromBuffer(ptr_response_buffer);
		if(!attach_response.result_)
			memcpy(result, attach_response.strIP_.toString().c_str(), attach_response.strIP_.toString().length());
		else
		{
			LOG( "get_register_server:receive message from register message queue success, but result is error! error_no [%d]!\n", attach_response.result_);
			boost::interprocess::message_queue::remove(ss.str().c_str());
			return;
		}
	}
	catch(boost::interprocess::interprocess_exception &ex)
	{
		boost::interprocess::message_queue::remove(ss.str().c_str());
		LOG( "get_register_server:use message queue error: %s\n", ex.what());
		return;
	}

	LOG( "get_register_server:receive register message queue result success!\n");
	boost::interprocess::message_queue::remove(ss.str().c_str());
}


int publish_single_data(const char *overlay_name, const char *resource_key, const char *resource_value)
{
	if(overlay_name == NULL || resource_key == NULL || resource_value == NULL)
		return 0;

	LOG( "publish_single_data: overlay_name %s,  resource_key %s\n", overlay_name, resource_key);

	boost::uuids::random_generator gen;
	boost::uuids::uuid publish_queue_id = gen();
	std::stringstream ss;
  ss << publish_queue_id;
	IPCCall::SendStoreReqIPCCallPacket request_packet;
	request_packet.messageQueueName_.setValue(ss.str());
	request_packet.overlayInstanceName_.setValue(overlay_name);
	request_packet.resourceName_.setValue(resource_key);

	IPCCall::StructVarArray<IPCCall::uint32, IPCCall::StoreKindData> kind_data;
	IPCCall::StoreKindData store_kind_data;
	store_kind_data.init(KINDID_GENERIC_SINGLE);
	store_kind_data.setSingleValueEntry(resource_value);
	kind_data.array_.push_back(store_kind_data);
	request_packet.kindData_ = kind_data;

	std::vector<IPCCall::byte> request_buffer(request_packet.size());
	boost::shared_ptr<IPCCall::IoBuffer> ptr_request_buffer(new IPCCall::IoBuffer(&request_buffer));
	ptr_request_buffer->clear();
	request_packet.writeToBuffer(ptr_request_buffer);

	try
	{
		boost::interprocess::message_queue::remove(ss.str().c_str());
		boost::interprocess::message_queue publish_queue(boost::interprocess::create_only, ss.str().c_str(), 10, IPCCall::maxMessageSize);

		LOG( "publish_single_data:create random publish message queue success, queue name [ %s ]!\n", ss.str().c_str());

		boost::interprocess::message_queue reload_queue(boost::interprocess::open_only, IPCCall::sendStoreReqMessageQueueName_.c_str());
		boost::posix_time::ptime current_time = boost::posix_time::second_clock::local_time();
		boost::posix_time::ptime end_time = current_time + boost::posix_time::seconds(10);
		if(!reload_queue.timed_send(&request_buffer[0], request_packet.size(), 0, end_time))
		{
			boost::interprocess::message_queue::remove(ss.str().c_str());
			LOG( "publish_single_data: reload message is full, can't send message timely!\n");
			return 0;
		}
		else
			LOG( "publish_single_data:open reload message queue success!\n");
		//reload_queue.send(request_buffer.data(), request_packet.size(), 0);

		std::vector<IPCCall::byte> response_buffer(IPCCall::maxMessageSize);
		boost::shared_ptr<IPCCall::IoBuffer> ptr_response_buffer(new IPCCall::IoBuffer(&response_buffer));
		ptr_response_buffer->clear();

		//boost::interprocess::message_queue register_queue(boost::interprocess::open_only, ss.str().c_str());
		unsigned int priority;
		std::size_t received_size;
		current_time = boost::posix_time::second_clock::local_time();
		end_time = current_time + boost::posix_time::seconds(10);
		if(!publish_queue.timed_receive(ptr_response_buffer->data(), ptr_response_buffer->capacity(),received_size,  priority , end_time))
		{
			boost::interprocess::message_queue::remove(ss.str().c_str());
			LOG( "publish_single_data: don't receive single data message int time!\n");
			return 0;
		}

		//publish_queue.receive(ptr_response_buffer->data(), ptr_response_buffer->capacity(),received_size,  priority );
		ptr_response_buffer->produce(received_size);
		IPCCall::IPCCallResultBase store_response;
		store_response.readFromBuffer(ptr_response_buffer);

		boost::interprocess::message_queue::remove(ss.str().c_str());

		if(!store_response.result_)
		{
			LOG( "publish_single_data: publish data in reload overlay successfully!\n");
			return 1;
		}
		else
		{
			LOG( "publish_single_data: publish data in reload overlay failed!\n");
			return 0;

		}
	}
	catch(boost::interprocess::interprocess_exception &ex)
	{
		boost::interprocess::message_queue::remove(ss.str().c_str());
		LOG( "publish_single_data: use message queue error: %s\n", ex.what());
		return 0;
	}
}

int publish_dictionary_data(const char *overlay_name, const char *dictionary_key, const char *map_key, const char *map_value)
{
	if(overlay_name == NULL || dictionary_key == NULL || map_key == NULL || map_value == NULL)
		return 0;

	boost::uuids::random_generator gen;
	boost::uuids::uuid publish_queue_id = gen();
	std::stringstream ss;
  ss << publish_queue_id;
	IPCCall::SendStoreReqIPCCallPacket request_packet;
	request_packet.messageQueueName_.setValue(ss.str());
	request_packet.overlayInstanceName_.setValue(overlay_name);
	request_packet.resourceName_.setValue(dictionary_key);

	IPCCall::StructVarArray<IPCCall::uint32, IPCCall::StoreKindData> kind_data;
	IPCCall::StoreKindData store_kind_data;
	store_kind_data.init(KINDID_GENERIC_DICTIONARY);
	store_kind_data.setDictionaryEntry(map_key, map_value);
	kind_data.array_.push_back(store_kind_data);
	request_packet.kindData_ = kind_data;

	std::vector<IPCCall::byte> request_buffer(request_packet.size());
	boost::shared_ptr<IPCCall::IoBuffer> ptr_request_buffer(new IPCCall::IoBuffer(&request_buffer));
	ptr_request_buffer->clear();
	request_packet.writeToBuffer(ptr_request_buffer);

	try
	{
		boost::interprocess::message_queue::remove(ss.str().c_str());
		boost::interprocess::message_queue publish_queue(boost::interprocess::create_only, ss.str().c_str(), 10, IPCCall::maxMessageSize);

		LOG( "publish_dictionary_data:create random publish message queue success, queue name [ %s ]!\n", ss.str().c_str());

		boost::interprocess::message_queue reload_queue(boost::interprocess::open_only, IPCCall::sendStoreReqMessageQueueName_.c_str());
		boost::posix_time::ptime current_time = boost::posix_time::second_clock::local_time();
		boost::posix_time::ptime end_time = current_time + boost::posix_time::seconds(10);
		if(!reload_queue.timed_send(&request_buffer[0], request_packet.size(), 0, end_time))
		{
			boost::interprocess::message_queue::remove(ss.str().c_str());
			LOG( "publish_dictionary_data: reload message is full, can't send message timely!\n");
			return 0;
		}
		else
			LOG( "publish_dictionary_data:open reload message queue success!\n");
		//reload_queue.send(request_buffer.data(), request_packet.size(), 0);

		std::vector<IPCCall::byte> response_buffer(IPCCall::maxMessageSize);
		boost::shared_ptr<IPCCall::IoBuffer> ptr_response_buffer(new IPCCall::IoBuffer(&response_buffer));
		ptr_response_buffer->clear();

		//boost::interprocess::message_queue register_queue(boost::interprocess::open_only, ss.str().c_str());
		unsigned int priority;
		std::size_t received_size;
		current_time = boost::posix_time::second_clock::local_time();
		end_time = current_time + boost::posix_time::seconds(10);
		if(!publish_queue.timed_receive(ptr_response_buffer->data(), ptr_response_buffer->capacity(),received_size,  priority, end_time))
		{
			boost::interprocess::message_queue::remove(ss.str().c_str());
			LOG( "publish_dictionary_data: don't receive publish message in time, we return directly!\n");
			return 0;
		}
		//publish_queue.receive(ptr_response_buffer->data(), ptr_response_buffer->capacity(),received_size,  priority );
		ptr_response_buffer->produce(received_size);
		IPCCall::IPCCallResultBase store_response;
		store_response.readFromBuffer(ptr_response_buffer);

		boost::interprocess::message_queue::remove(ss.str().c_str());

		if(!store_response.result_)
		{
			LOG( "publish_dictionary_data: publish data in reload overlay successfully!\n");
			return 1;
		}
		else
		{
			LOG( "publish_dictionary_data: publish data in reload overlay failed!\n");
			return 0;

		}
	}
	catch(boost::interprocess::interprocess_exception &ex)
	{
		boost::interprocess::message_queue::remove(ss.str().c_str());
		LOG( "publish_dictionary_data: use message queue error: %s\n", ex.what());
		return 0;
	}

}

void delete_dictionary_data(const char *overlay_name, const char *dictionary_key, const char *map_key)
{
	if(overlay_name == NULL || dictionary_key == NULL || map_key == NULL)
		return;

}

void get_data(const char *overlay_name, const char *resource_key, IPCCall::SendFetchReqIPCCallResult &store_result, int is_single_data)
{
	if(overlay_name == NULL || resource_key == NULL)
			return;

		LOG( "get_data: overlay_name %s,  resource_key %s\n", overlay_name, resource_key);

		boost::uuids::random_generator gen;
		boost::uuids::uuid publish_queue_id = gen();
		std::stringstream ss;
	  ss << publish_queue_id;
		IPCCall::SendFetchReqIPCCallPacket request_packet;
		IPCCall::StoredDataSpecifier specifier;
		request_packet.messageQueueName_.setValue(ss.str());
		request_packet.overlayInstanceName_.setValue(overlay_name);
		request_packet.resourceName_.setValue(resource_key);
		if(is_single_data)
			specifier.init(KINDID_GENERIC_SINGLE);
		else
			specifier.init(KINDID_GENERIC_DICTIONARY);
		request_packet.specifiers_.array_.push_back(specifier);

		std::vector<IPCCall::byte> request_buffer(request_packet.size());
		boost::shared_ptr<IPCCall::IoBuffer> ptr_request_buffer(new IPCCall::IoBuffer(&request_buffer));
		ptr_request_buffer->clear();
		request_packet.writeToBuffer(ptr_request_buffer);

		try
		{
			boost::interprocess::message_queue::remove(ss.str().c_str());
			boost::interprocess::message_queue publish_queue(boost::interprocess::create_only, ss.str().c_str(), 10, IPCCall::maxMessageSize);

			LOG( "get_data:create random fetch message queue success, queue name [ %s ]!\n", ss.str().c_str());

			boost::interprocess::message_queue reload_queue(boost::interprocess::open_only, IPCCall::sendFetchReqMessageQueueName_.c_str());
			boost::posix_time::ptime current_time = boost::posix_time::second_clock::local_time();
			boost::posix_time::ptime end_time = current_time + boost::posix_time::seconds(10);
			if(!reload_queue.timed_send(&request_buffer[0], request_packet.size(), 0, end_time))
			{
				boost::interprocess::message_queue::remove(ss.str().c_str());
				LOG( "get_data: reload message is full, can't send message timely!\n");
				return;
			}
			else
				LOG( "get_data:open reload message queue success!\n");
			//reload_queue.send(request_buffer.data(), request_packet.size(), 0);
			std::vector<IPCCall::byte> response_buffer(IPCCall::maxMessageSize);
			boost::shared_ptr<IPCCall::IoBuffer> ptr_response_buffer(new IPCCall::IoBuffer(&response_buffer));
			ptr_response_buffer->clear();

			//boost::interprocess::message_queue register_queue(boost::interprocess::open_only, ss.str().c_str());
			unsigned int priority;
			std::size_t received_size;
			current_time = boost::posix_time::second_clock::local_time();
			end_time = current_time + boost::posix_time::seconds(10);
			if(!publish_queue.timed_receive(ptr_response_buffer->data(), ptr_response_buffer->capacity(),received_size,  priority, end_time))
			{
				boost::interprocess::message_queue::remove(ss.str().c_str());
				LOG( "get_data: don't receive result message int time, we directly return!\n");
				return;
			}

			//publish_queue.receive(ptr_response_buffer->data(), ptr_response_buffer->capacity(),received_size,  priority );
			ptr_response_buffer->produce(received_size);
			IPCCall::SendFetchReqIPCCallResult store_response;
			store_response.readFromBuffer(ptr_response_buffer);
			store_result = store_response;

			boost::interprocess::message_queue::remove(ss.str().c_str());
		}
		catch(boost::interprocess::interprocess_exception &ex)
		{
			boost::interprocess::message_queue::remove(ss.str().c_str());
			LOG( "get_data: use message queue error: %s\n", ex.what());
		}
}

void get_single_data(const char *overlay_name, const char *resource_key, char *result)
{
	if(overlay_name == NULL || resource_key == NULL || result == NULL)
			return;
	IPCCall::SendFetchReqIPCCallResult store_result;
	store_result.result_ = -1;
	get_data(overlay_name, resource_key, store_result, 1);

	if(!store_result.result_)
	{
		for(std::size_t i = 0; i < store_result.kindResponses_.array_.size(); ++i)
		{
			if(store_result.kindResponses_.array_[i].kind_ == KINDID_GENERIC_SINGLE)
			{
				IPCCall::StoredDataPtr store_data_ptr;
				store_result.kindResponses_.array_[i].getSingleValueEntry(store_data_ptr);
				if(store_data_ptr.pDataValue_ != NULL && store_data_ptr.pDataValue_->exists_ == IPCCall::Boolean_True && store_data_ptr.pDataValue_->value_.array_.size() >0)
				{
					memcpy(result, store_data_ptr.pDataValue_->toString().c_str(), store_data_ptr.pDataValue_->toString().length() + 1);
				}
				break;
			}
		}
	}
	else
	{
		LOG( "get_single_data: get data from reload overlay failed!\n");
	}

}

void get_dictionary_data(const char *overlay_name, int is_local_overlay, const char *resource_key, void *result)
{
	if(overlay_name == NULL || resource_key == NULL || result == NULL)
		return;
	//char *result_begin = result;
	std::string shost;
	IPCCall::SendFetchReqIPCCallResult store_result;
	store_result.result_ = -1;
	get_data(overlay_name, resource_key, store_result, 0);

	LOG( "get_dictionary_data: resource_key %s!\n", resource_key);

	if(!store_result.result_)
	{
		for(std::size_t i = 0; i < store_result.kindResponses_.array_.size(); ++i)
		{
			if(store_result.kindResponses_.array_[i].kind_ == KINDID_GENERIC_DICTIONARY)
			{
				boost::posix_time::ptime gregorian_time(boost::gregorian::date(1970, boost::date_time::Jan, 1));
				long int update_time = (boost::posix_time::microsec_clock::local_time() - gregorian_time - boost::posix_time::seconds(5*60+30)).total_milliseconds();
				for(std::list<IPCCall::StoredData>::iterator it = store_result.kindResponses_.array_[i].values_.list_.begin();
						it != store_result.kindResponses_.array_[i].values_.list_.end(); ++it )
				{
					if(it->value_.arrayEntry_.value_.exists_ == IPCCall::Boolean_True)
					{
						if(it->storageTime_ < update_time)//the record is over time
						{
							LOG( "get_dictionary_data:the icscf address record is over time, we don't take it!\n");
							continue;
						}
						if(is_local_overlay)
						{
							shost = it->value_.dictionaryEntry_.value_.toString();
							LOG( "get_dictionary_data: get data %.*s!\n", shost.length(), shost.c_str());
						}
						else
						{
							//only excuted in icscf to query domain icscf list
							//if(result + shost.len + 1 - result_begin < MAX_ARRAY_LENGTH)//result length is default 1024
							//{
								//memcpy(result, shost.s, shost.len);
								//result += shost.len;
								//*result = ';';//use ';' as split between icscf address
								//++result;
							//}
						}
					}
				}

				break;
			}
		}
	}
	else
	{
		LOG( "get_dictionary_data: get data from reload overlay failed!\n");
	}
}
